import socket
import base64
import hashlib
import time
import struct

COD = 'utf-8'
HOST = 'localhost' # 主机ip
PORT = 9090 # 软件端口号
BUFSIZ = 1024
ADDR = (HOST, PORT)
SIZE = 10 

def get_headers(data):
    """
    将请求头格式化成字典
    :param data:
    :return:
    """
    header_dict = {}
    data = str(data, encoding='utf-8')
 
    header, body = data.split('\r\n\r\n', 1)
    header_list = header.split('\r\n')
    for i in range(0, len(header_list)):
        if i == 0:
            if len(header_list[i].split(' ')) == 3:
                header_dict['method'], header_dict['url'], header_dict['protocol'] = header_list[i].split(' ')
        else:
            k, v = header_list[i].split(':', 1)
            header_dict[k] = v.strip()
    return header_dict

class mySocket:
  
    tcp_server_socket = None
    new_socket = None
    ip_port = None

    def __init__(self,host,port):
        # 1. 创建tcp服务端套接字对象
        self.tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        # 设置端口号复用，通俗理解程序退出端口号立即释放
        # 1. SOL_SOCKET表示当前套接字
        # 2. SO_REUSEADDR表示复用选项
        # 3. 是否复用，True表示复用
        self.tcp_server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
        # 2. 绑定端口号, "localhost"： 表示本机， 8989： 端口号
        self.tcp_server_socket.bind((host, port))
        # 3. 设置监听, 128: 表示最大等待的连接个数
        self.tcp_server_socket.listen(128)
        self.start()
      
    def start(self):
        while True:
            print("服务器启动，监听客户端链接")
            # 4. 等待接受客户的连接请求
            self.new_socket,self.ip_port = self.tcp_server_socket.accept()
            print("链接的客户端:", self.ip_port)
            data = self.new_socket.recv(BUFSIZ)

            headers = get_headers(data)
            response_tpl = "HTTP/1.1 101 Switching Protocols\r\n" \
                        "Upgrade:websocket\r\n" \
                        "Connection:Upgrade\r\n" \
                        "Sec-WebSocket-Accept:%s\r\n" \
                        "WebSocket-Location:ws://%s%s\r\n\r\n"
        
            value = headers['Sec-WebSocket-Key'] + '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'

            ac = base64.b64encode(hashlib.sha1(value.encode('utf-8')).digest())

            response_str = response_tpl % (ac.decode('utf-8'), headers['Host'], headers['url'])

            self.new_socket.send(bytes(response_str, encoding='utf-8'))

            while True:
                try:
                    info = self.new_socket.recv(8096)
                    info2 = self.new_socket.recv(BUFSIZ)
                    print("客户端接收 未转码的内容:",info2)
                except Exception as e:
                    info = None
                if not info:
                    break
                payload_len = info[1] & 127
                if payload_len == 126:
                    extend_payload_len = info[2:4]
                    mask = info[4:8]
                    decoded = info[8:]
                elif payload_len == 127:
                    extend_payload_len = info[2:10]
                    mask = info[10:14]
                    decoded = info[14:]
                else:
                    extend_payload_len = None
                    mask = info[2:6]
                    decoded = info[6:]
                bytes_list = bytearray()
                for i in range(len(decoded)):
                    chunk = decoded[i] ^ mask[i % 4]
                    bytes_list.append(chunk)
                try:
                    body = str(bytes_list, encoding='utf-8')
                    # self.send(body.encode('utf-8'))
                    print('客户端接收内容:',body)
                except Exception as e:
                    break
            # while True:
            #     try:
            #         data = self.new_socket.recv(BUFSIZ) # 读取已链接客户的发送的消息
            #         data_len = len(data)
            #     except Exception:
            #         print("断开的客户端", self.ip_port)
            #         break
            # print("客户端发送的内容:",data.decode(COD))
            # if not data:
            #     break
            # # 对二进制数据进行解码
            # msg = time.strftime("%Y-%m-%d %X") #获取结构化事件戳
            # msg1 = '[%s]:%s' % (msg, data.decode(COD))
            # self.new_socket.send(msg1.encode(COD)) #发送消息给已链接客户端

           
    def close(self):
        # 服务端的套接字关闭，不再提供连接服务
        self.tcp_server_socket.close()

    def send(self,content):
        """
        WebSocket服务端向客户端发送消息
        :param conn: 客户端连接到服务器端的socket对象,即： conn,address = socket.accept()
        :param msg_bytes: 向客户端发送的字节
        :return:
        """
        token = b"\x81"

        length = len(content)
        if length < 126:
            token += struct.pack("B", length)
        elif length <= 0xFFFF:
            token += struct.pack("!BH", 126, length)
        else:
            token += struct.pack("!BQ", 127, length)

        data = token + content
        # 对字符串进行编码
        # data = content.encode(COD)
        # 发送给客户端的数据
        self.new_socket.send(data)
        # 关闭和客户端通信的socket
        # self.new_socket.close()
        return True


if __name__ == '__main__':
    s = mySocket(HOST,PORT)